#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "lockgroup.hpp"
#include "LOG.hpp"
#include <string.h>
#include <string>
#include "InetAddr.h"
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <functional>

using namespace std;

enum
{
    SOCKET_ERROR = 0,
    BIND_ERROR,
    USEGE_ERROR,
    READ_ERROR,
    LISTEN_ERROR
};


using func_t = function<string(string)>;

class Tcpsever;

class ThreadData
{
public:
    ThreadData(int socket,InetAddr client,Tcpsever* self)
    :_socket(socket)
    ,_client(client)
    ,_self(self)
    {}

public:
    int _socket;
    InetAddr _client;
    Tcpsever* _self;
};
class Tcpsever
{

public:
    Tcpsever(uint16_t port,func_t func)
        : _port(port)
        , _func(func)
    {
    }
    void InitSever()
    {
        // 1.建立套接字
        _listensocket = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensocket < 0)
        {
            LOG(FATAL, "_listensocket fail");
            exit(SOCKET_ERROR);
        }
        LOG(INFO, "_listensocket success: %d", _listensocket);

        // 2.bind
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_port = htons(_port);
        int n = bind(_listensocket, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind fail");
            exit(BIND_ERROR);
        }
        LOG(INFO, "bind success");

        // 3.tcp面向连接，所以需要先建立连接
        //_socket转成listen状态
        n = listen(_listensocket, 0);
        if (n < 0)
        {
            LOG(FATAL, "listen fail");
            exit(LISTEN_ERROR);
        }
    }
    void Service(int socket, InetAddr client)
    {
        // 5.获取连接后，通信（收消息，发消息）
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Ip().c_str(), client.Port(), socket);
        while (1)
        {
            // LOG(INFO,"%s:%d send a message: ",client.Ip().c_str(),client.Port());
            string message_client = "[" + client.Ip() + " : " + to_string(client.Port()) + "]" + "send a message: ";
            char buffer[1024];
            ssize_t n = read(socket, buffer, sizeof(buffer));
            if (n > 0)
            {
                // 证明收到消息
                buffer[n] = 0;
                cout << message_client << buffer << endl;

                // 发消息给用户
                string message_sever = "sever echo: ";
                message_sever += buffer;

                write(socket, message_sever.c_str(), message_sever.size());
            }
            else if (n == 0)
            {
                // client退出 && 连接关闭
                LOG(INFO, "client quit");
                break;
            }
            else
            {
                LOG(ERROR, "read error");
                break;
            }
        }
        close(socket);
    }

    static void* handler(void* args)
    {
        ThreadData* data = static_cast<ThreadData*>(args);
        data->_self->Service(data->_socket,data->_client);

        delete data;
        return nullptr;
    }

    void Loop()
    {
        // 4.不能直接接收数据，要先获取连接
        _isrunning = true;
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int socket = accept(_listensocket, (struct sockaddr *)&peer, &len);
            if (socket < 0)
            {
                LOG(WARNING, "accept fail");
                sleep(1);
                continue;
            }
            LOG(INFO, "accept success:%d", socket);

            // vesion 0 :问题，如果客户一直不退出，Service不返回，所以循环进行不下去
            // 一次只能处理一个请求 （不可能）
            // Service(socket,InetAddr(peer));

            // vesion 1:多进程
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // child 管内部业务
            //     close(_listensocket);
            //     if (fork() > 0)
            //         exit(0);                     // 就是让子进程退出
            //     Service(socket, InetAddr(peer)); // 孙子进程，走到这里子进程退出了，它就交给系统托管
            //     exit(0);
            // }
            // // father 管监听
            // close(socket);
            // waitpid(id, nullptr,0);


            //vesion 2:多线程
            pthread_t tid;
            ThreadData* data = new ThreadData(socket,InetAddr(peer),this);
            pthread_create(&tid,nullptr,handler,data);
        }
        _isrunning = false;
    }
    ~Tcpsever()
    {
    }

private:
    uint16_t _port;
    int _listensocket;
    bool _isrunning;

    func_t _func;
};